<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of Model
 *
 * @author mateusz.ledzewicz
 */
abstract class Model {
    //put your code here
    protected static $pdo=null;
    public  $NewRecord;
    public  $labels;
    private $isJoined = false;
    private $beginTransaction = false; 
    
    abstract protected function getTableName();
    abstract protected function getPrimaryKey();
    abstract public function getColumns();
    abstract protected function getBoolColumns();
    abstract protected function getJoinTables();
    
    public function __construct($id = null, $joins=null) {
        self::$pdo = Mypdo::getInstance();
        //$models = array($name=>$this);
        //$joins[] = $name;
        /*
         * Array z modelami 
         * Petla po modelach i uzupełnienie danymi 
         * Jeżeli Null to wstawia null
         * 
         */
        
        if($id){
            $this->NewRecord = false;
            if(is_null($joins)){
                $this -> getData($id);
            } else if(empty ($joins)){
                $this->getDataFullJoin($id);
            } else {
                $this-> getDataJoin($id, $joins);
            }
        } else {
            $this->NewRecord = true;
        } 
    }
    
    public function setValues($table, $ignore=array(), $key_change=array(), $autoFalse = true){
        $valuesToSet = array();
        
        foreach($table as $key => $value){
            $keyArray = explode(ConfigSuffix::sqlParamSeparator, $key);
            $param = ( count($keyArray) > 1) ? $keyArray[1] : $key;
            $class = ( count($keyArray) > 1) ? $keyArray[0] : null;
            if(is_null($class) || strtolower($class) == strtolower(get_class($this)) )
                $valuesToSet[$param] = $value;
        }
        
        if($autoFalse){
            foreach ($this ->getBoolColumns() as $col){
                $this -> $col = false;
            }
        }
        
        foreach($valuesToSet as $key => &$value){
            if(in_array($key, $ignore))
                    continue;
            
            if(array_key_exists($key, $key_change))
				$key = $key_change[$key];
			               
			if(property_exists(get_class($this), $key))
				$this -> $key  = $value;
            
        }
    }
        
    public function clearValues($params){
        foreach($params as $param){
            if(property_exists(get_class($this), $param))
                $this->$param = null;
        }
    }

    public function save(){
        /*
         *Z paramtetrem all save wszystkich  
         */
        $return = $this->beforeSave();
        if(!self::$pdo -> inTransaction()){
            $this->beginTransaction = true;
            self::$pdo -> beginTransaction();
        }

        $return = $this -> systemBeforeSave() && $return;
        
        if($return){
            if($this->NewRecord)
                $return = $this->insert();
            else 
                $return = $this->update();
        }
        if($this->beginTransaction){
            if(!$return){
                self::$pdo -> rollback();
            }else{ 
                self::$pdo -> commit();
            }
        }
        $this->afterSave();
        return $return;
      
    }
    
    public function deleteIf($condition){
        return $this -> pdo -> exec("DELETE FROM {$this->getTableName()} WHERE $condition");
    }
    
    public function  delete(){
        return $this->deleteIf("{$this->getPrimaryKey()} = {$this->{$this ->getPrimaryKey()}}");
    }

    public function setLabels($arrayOfLabels){
        $this->labels = array_merge($this->labels, $arrayOfLabels);
    }
    
    public function isUnique($column, $ignore=array()){
        $condition = '';
        foreach($ignore as $key => $value){
            $condition .= " AND $key <> $value";
        }
        $result = self::$pdo -> query(
       "SELECT * FROM {$this -> getTableName()} WHERE $column = '{$this->$column}'
        AND {$this -> getPrimaryKey()} != '{$this -> {$this -> getPrimaryKey()}}' $condition");
        
        if($result->rowCount()>0)
            return false;
        return true;
    }

    protected function insert(){
        $params = '';
        $values = '';
        foreach($this ->getColumns() as $col){
            if($col == $this ->getPrimaryKey() || is_null($this -> $col))
                continue;
            
            $params .= "$col, ";
            $values .= ":$col, ";
        }
        $params = rtrim($params, ', ');
        $values = rtrim($values, ', ');
        
        $stmt = self::$pdo->prepare("INSERT INTO {$this -> getTableName()} ($params) VALUES ($values)");
       foreach($this ->getColumns() as $col){
            if($col == $this ->getPrimaryKey() || is_null($this -> $col))
                continue;
            
            if(in_array($col, $this->getBoolColumns()) )
                $stmt -> bindValue(":$col", $this->$col, PDO::PARAM_BOOL );
            else
                $stmt -> bindValue(":$col", $this->$col);
        }
        $exec = $stmt ->execute();
        if($exec){
            $this->{$this->getPrimaryKey()} = self::$pdo -> lastInsertId();
            $this->NewRecord = false;
        }
        return $exec;
    }
    
    protected function update(){
        $query = '';
        foreach($this -> getColumns() as $col){
            if($col == $this->getPrimaryKey())
                continue;
            $query .= "$col = :$col, ";
        }
        $query = rtrim($query, ', ');
        $primaryKey = $this->getPrimaryKey();
        $stmt = self::$pdo -> prepare("UPDATE {$this->getTableName()} SET $query WHERE $primaryKey = {$this -> $primaryKey}");
        
        foreach($this -> getColumns() as $col){
            if($col == $this->getPrimaryKey())
                continue;

            if(in_array($col, $this->getBoolColumns()) )
                $stmt -> bindValue(":$col", $this->$col, PDO::PARAM_BOOL );
            else if(is_null($this -> $col))
                 $stmt -> bindValue(":$col", $this->$col, PDO::PARAM_NULL );
            else
                $stmt -> bindValue(":$col", $this->$col);    
        }
        return $stmt -> execute();
    }
    protected function beforeSave(){ return true;}
    protected function afterSave(){ return true;}
    
    public static function getAll($table_name, $where=null){
		$array = array();
		$stmt = self::$pdo -> query("SELECT * FROM {$table_name} $where");
		while($row = $stmt -> fetchObject(ucfirst($table_name)))
		{
			$id = $row -> getPrimaryKey();
			$row -> NewRecord = false;
			$array[$row -> $id] = $row;
		}
		return $array;
    }
   
    
    private function prepareSqlParams($models){
        $paramQuery = '';
        $models[] = $this;
        foreach ($models as $model){
            $modelName = strtolower(get_class($model));
            foreach($model->getColumns() as $col){
                    $paramQuery .= "$modelName.$col as $modelName".ConfigSuffix::sqlParamSeparator."$col, ";
                }
        }
        $paramQuery = rtrim($paramQuery, ', ');
        return $paramQuery;
    }
    
    private function getData($id){
        
        $data = self::$pdo->query("SELECT * FROM {$this->getTableName()} WHERE {$this -> getPrimaryKey()} = '$id'");    
        

            
        if($data = $data -> fetch(PDO::FETCH_ASSOC)){
            $this->SetValues($data);
        } 
    }
    
    private function getDataJoin($id, $joins){
            $this->isJoined = true;
            $models = array();
            $name = strtolower(get_class($this));
            $joinQuery = '';
            foreach($joins as $join){            
               $modelName = ucfirst(strtolower($join));
               $model = new $modelName;
               $models[$modelName] = $model;
               $joinQuery .= 'join '.$modelName.' on '.$modelName.'.'.$model->getPrimaryKey().' = '.$name.'.'.$model->getPrimaryKey()."\n";
            }
            
            $data = self::$pdo->query("SELECT {$this->prepareSqlParams($models)} FROM {$this->getTableName()} $joinQuery  WHERE $name.{$this -> getPrimaryKey()} = '$id'");
            
           
            if($data = $data -> fetch(PDO::FETCH_ASSOC)){
                $this->SetValues($data);
                foreach($models as $modelToSave){ 
                    $modelToSave -> SetValues($data);
                    $modelToSave -> NewRecord = false;
                    if($modelToSave->isNull()){
                        $this -> {$model->getPrimaryKey()} = null;
                    } else {
                        $this -> {$model->getPrimaryKey()} = $model;
                    }
                }
            } 
    }
    
    private function getDataFullJoin($id){
        $joinTables = $this ->getJoinTables();
        if(count($joinTables) > 0){
            return $this ->getDataJoin($id, $joinTables);
        } else {
            return $this->getData($id);
        }
    }
    
    public function isNull(){
        return (!$this -> NewRecord && $this -> {$this ->getPrimaryKey()} == null);
    }
    
    private function systemBeforeSave(){
        
        foreach($this->getColumns() as $col){
            $value = $this -> $col;
            if($value instanceof Model ){
                if($value -> NewRecord || $this -> isJoined){
                   if(!$value->save())
                       return false;
                   $this -> $col = $value -> {$value -> getPrimaryKey()};
                } else {
                    $this -> $col = $value -> {$value -> getPrimaryKey()};
                }
            }
        } 
        return true;
    }

   
            
    
    
}

?>
